#include "pthreadPool.h"
#include "workCmd.h"
#include "md5.h"

int mysqlConnect(MYSQL **pconn){
    char *host = "localhost";
    char *user = "root";
    char *passwd = "1234";
    char *db = "netDisk";

    *pconn = mysql_init(NULL);
    if(mysql_real_connect(*pconn,host,user,passwd,db,0,NULL,0) == NULL){
        printf("Error:%s\n",mysql_error(*pconn));
        mysql_close(*pconn);
        return EXIT_FAILURE;
    }
    printf("MYSQL connect success!\n");
    return 0;
}

int doQuery(char *query,MYSQL **pconn){
    int ret = mysql_query(*pconn,query);
    if(ret != 0){
        printf("Error query:%s\n",mysql_error(*pconn));
        return EXIT_FAILURE;
    }
    return 0;
}

//用户表操作
int getUserId(char *userName,int *puserId){
    MYSQL *conn;
    int ret = mysqlConnect(&conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    ret = mysql_query(conn, "set names 'utf8'");
    if(ret != 0){
        printf("error query1:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    ret = doQuery("select username, id from clientInfo", &conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    MYSQL_RES *result = mysql_use_result(conn);
    if(result == NULL){
        printf("error result: %s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    MYSQL_ROW row;
    while((row = mysql_fetch_row(result)) != NULL){
        if(strcmp(row[0], userName) == 0){
            *puserId = atoi(row[1]);

            mysql_free_result(result);
            mysql_close(conn);
            return 0;
        }
    }
    mysql_free_result(result);
    mysql_close(conn);
    return EXIT_FAILURE;
}

int getUserName(char *userName,int userId){
    MYSQL *conn;
    int ret = mysqlConnect(&conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    ret = mysql_query(conn, "set names 'utf8'");
    if(ret != 0){
        printf("error query1:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    ret = doQuery("select username, id from clientInfo", &conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    MYSQL_RES *result = mysql_use_result(conn);
    if(result == NULL){
        printf("error result: %s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    MYSQL_ROW row;
    while((row = mysql_fetch_row(result)) != NULL)
    {
        if(userId == atoi(row[1])){
            strcpy(userName, row[0]);

            mysql_free_result(result);
            mysql_close(conn);
            return 0;
        }
    }
    mysql_free_result(result);
    mysql_close(conn);
    return EXIT_FAILURE;
}

int getUserSalt(char *userName,char *salt, char *cryptPasswd){
    MYSQL *conn;
    int ret = mysqlConnect(&conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    ret = mysql_query(conn, "set names 'utf8'");
    if(ret != 0){
        printf("error query1:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    ret = doQuery("select username, salt, cryptpasswd from clientInfo", &conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    MYSQL_RES *result = mysql_use_result(conn);
    if(result == NULL){
        printf("error result: %s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    MYSQL_ROW row;
    while((row = mysql_fetch_row(result)) != NULL){
        if(strcmp(row[0], userName) == 0){
            strcpy(salt, row[1]);
            strcpy(cryptPasswd, row[2]);
            mysql_free_result(result);
            mysql_close(conn);
            return 0;
        }
    }
    mysql_free_result(result);
    mysql_close(conn);
    return EXIT_FAILURE;
}

int getUserCode(int userId,int *pcode){
    MYSQL *conn;
    int ret = mysqlConnect(&conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    ret = doQuery("select code, id from clientInfo", &conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    MYSQL_RES *result = mysql_use_result(conn);
    if(result == NULL){
        printf("error result: %s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    MYSQL_ROW row;
    while((row = mysql_fetch_row(result)) != NULL){
        if(userId == atoi(row[1])){
            *pcode = atoi(row[0]);

            mysql_free_result(result);
            mysql_close(conn);
            return 0;
        }
    }
    mysql_free_result(result);
    mysql_close(conn);
    return EXIT_FAILURE;

}

int getUserPwd(int userId,char *pwd){
    MYSQL *conn;
    int ret = mysqlConnect(&conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    ret = mysql_query(conn, "set names 'utf8'");
    if(ret != 0){
        printf("error query1:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    ret = doQuery("select pwd, id from clientInfo", &conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    MYSQL_RES *result = mysql_use_result(conn);
    if(result == NULL){
        printf("error result: %s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    MYSQL_ROW row;
    while((row = mysql_fetch_row(result)) != NULL){
        if(userId == atoi(row[1])){
            strcpy(pwd, row[0]);

            mysql_free_result(result);
            mysql_close(conn);
            return 0;
        }
    }
    mysql_free_result(result);
    mysql_close(conn);
    return EXIT_FAILURE;
}

int updateUserPwd(int userId,char *pwd,int code){
    MYSQL *conn;
    int ret = mysqlConnect(&conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    ret = mysql_query(conn, "set names 'utf8'");
    if(ret != 0){
        printf("error query1:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    char query[1024] = {0};
    sprintf(query, "update clientInfo set pwd = '%s' where id = %d", pwd, userId);
    ret = doQuery(query, &conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    bzero(query, sizeof(query));
    sprintf(query, "update clientInfo set code = %d where id = %d", code, userId);
    ret = doQuery(query, &conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }

    mysql_close(conn);
    return EXIT_FAILURE;
}


//虚拟文件表操作
int initLocalFile(){
    // 连接数据库
    MYSQL *conn;
    int ret = mysqlConnect(&conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    ret = mysql_query(conn, "set names 'utf8'");
    if(ret != 0){
        printf("error query1:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    char query[1024] = {0};

    // 读取目录流，获取本地存储目录中的每个文件
    DIR *dirp = opendir("NetDisk");
    ERROR_CHECK(dirp, NULL, "opendir");
    struct dirent *pdirent;
    char md5Str[MD5_STR_LEN + 1] = {0};// 这里长度需要加1，存结束符

    while ((pdirent = readdir(dirp)) != NULL)
    {
        // 跳过隐藏文件
        if (*(pdirent->d_name) == '.'){
            continue;
        }
        char realName[100] = {0};
        strcpy(realName, pdirent->d_name);
        sprintf(query, "select * from localFiles where realFileName like '%s'", realName);
        ret = doQuery(query, &conn);
        if (ret != 0){
            return EXIT_FAILURE;
        }
        MYSQL_RES *result = mysql_store_result(conn); // 这里如果用use不会真正获得数据，rows仍为0
        if (ret != 0){
            printf("error query:%s\n", mysql_error(conn));
            return EXIT_FAILURE;
        }
        int rows = mysql_num_rows(result);
        if (rows != 0){
            // 文件名存在就继续读
            mysql_free_result(result);
            continue;
        }
        mysql_free_result(result);

        // 文件名不存在则计算md5值，插入本地
        char path[1024] = {0};
        sprintf(path, "%s%s%s", "NetDisk", "/", pdirent->d_name);
        bzero(md5Str, sizeof(md5Str));
        Compute_file_md5(path, md5Str);
        bzero(query, sizeof(query));
        sprintf(query, "insert into localFiles(md5, linkNum, realFileName) values('%s', 0, '%s')", md5Str, pdirent->d_name);
        ret = doQuery(query, &conn);
        if (ret != 0){
            return EXIT_FAILURE;
        }
    }
    mysql_close(conn);
    return 0;

}

// 增加链接数
int addLink(char *md5Str){
    MYSQL *conn;
    int ret = mysqlConnect(&conn);
    int linkNum;
    if(ret != 0){
        return EXIT_FAILURE;
    }
    char query[1024] = {0};

    // 获得当前链接数
    bzero(query, sizeof(query));
    sprintf(query, "select linkNum from localFiles where md5 like '%s'", md5Str);
    ret = doQuery(query, &conn);
    if (ret != 0){
        return EXIT_FAILURE;
    }
    MYSQL_RES *result = mysql_use_result(conn);
    if (ret != 0){
        printf("error query:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    MYSQL_ROW row;
    if((row = mysql_fetch_row(result)) == NULL){
        printf("error query:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    linkNum = atoi(row[0]);// 获得目前的链接数

    mysql_free_result(result);// 查询完要先释放查询结果，否则无法更新表格
    ++linkNum;
    bzero(query, sizeof(query));
    sprintf(query, "update localFiles set linkNum = %d where md5 like '%s'", linkNum, md5Str);

    ret = doQuery(query, &conn);
    if (ret != 0){
        return EXIT_FAILURE;
    }
    mysql_close(conn);
    return 0;
}

// 减少链接数
int minusLink(char *md5Str){
    MYSQL *conn;
    int ret = mysqlConnect(&conn);
    int linkNum;
    if(ret != 0){
        return EXIT_FAILURE;
    }
    char query[1024] = {0};

    // 查询文件是否已在表中存在
    bzero(query, sizeof(query));
    sprintf(query, "select linkNum from localFiles where md5 like '%s'", md5Str);
    ret = doQuery(query, &conn);
    if (ret != 0){
        return EXIT_FAILURE;
    }
    MYSQL_RES *result = mysql_use_result(conn);
    if (ret != 0){
        printf("error query:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    MYSQL_ROW row;
    if((row = mysql_fetch_row(result)) == NULL){
        printf("error query:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    linkNum = atoi(row[0]);// 获得目前的链接数

    mysql_free_result(result);// 查询完要先释放查询结果，否则无法更新表格
    --linkNum;
    if(linkNum < 0){
        printf("error minus link_num!\n");
        return EXIT_FAILURE;
    }
    bzero(query, sizeof(query));
    sprintf(query, "update localFiles set linkNum = %d where md5 like '%s'", linkNum, md5Str);
    ret = doQuery(query, &conn);
    if (ret != 0){
        return EXIT_FAILURE;
    }
    mysql_close(conn);
    return 0;
}

// 获取文件md5值，也可以检查文件是否存在，存在返回0，不存在返回1
int getVirtualFileMd5(char *file, int userId, int parentId, char *md5Str){
    MYSQL *conn;
    int ret = mysqlConnect(&conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    ret = mysql_query(conn, "set names 'utf8'");
    if(ret != 0){
        printf("error query1:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    char query[1024] = {0};
    sprintf(query, "select md5 from virtualFile where ownerId = %d and fileName like '%s' and parentId = %d", userId, file, parentId);
    ret = doQuery(query, &conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    MYSQL_RES *result = mysql_use_result(conn);
    if(result == NULL){
        printf("error result: %s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    
    MYSQL_ROW row;
    if((row = mysql_fetch_row(result)) == NULL)// 不存在则直接返回
    {
        return EXIT_FAILURE;
    }
    strcpy(md5Str, row[0]);
    mysql_free_result(result);
    mysql_close(conn);
    return 0;
}

// 获取文件本地真实名称
int getRealFileName(char *md5Str, char *realFileName){
    MYSQL *conn;
    int ret = mysqlConnect(&conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    ret = mysql_query(conn, "set names 'utf8'");
    if(ret != 0){
        printf("error query1:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    char query[1024] = {0};

    // 按照md5值在表中查找本地文件名
    bzero(query, sizeof(query));
    sprintf(query, "select realFileName from localFiles where md5 like '%s'", md5Str);
    ret = doQuery(query, &conn);
    if (ret != 0){
        return EXIT_FAILURE;
    }
    MYSQL_RES *result = mysql_store_result(conn);
    if(result == NULL){
        printf("error result: %s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    int rows = mysql_num_rows(result);
    if(rows == 0){
        // 文件不存在返回1
        mysql_free_result(result);
        mysql_close(conn);
        return 1;
    }
    MYSQL_ROW row;
    if((row = mysql_fetch_row(result)) == NULL){
        printf("error query:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    strcpy(realFileName, row[0]);
    mysql_free_result(result);
    mysql_close(conn);
    return 0;
}

int getFileCode(int userId, char *fileName, int *pcode, int parentId, char *type){
    MYSQL *conn;
    int ret = mysqlConnect(&conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    ret = mysql_query(conn, "set names 'utf8'");
    if(ret != 0){
        printf("error query1:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    char query[1024] = {0};
    sprintf(query, "select id, parentId, type from virtualFile where ownerId = %d and fileName like '%s' and parentId = %d", userId, fileName, parentId);
    ret = doQuery(query, &conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    MYSQL_RES *result = mysql_use_result(conn);
    if(result == NULL){
        printf("error result: %s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    MYSQL_ROW row;
    if((row = mysql_fetch_row(result)) == NULL){
        // 不存在直接返回
        return EXIT_FAILURE;
    }
    *pcode = atoi(row[0]);
    strcpy(type, row[2]);
    mysql_free_result(result);
    mysql_close(conn);
    return 0;
}

int getParentId(int id, int *pparentCode){
    MYSQL *conn;
    int ret = mysqlConnect(&conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    ret = mysql_query(conn, "set names 'utf8'");
    if(ret != 0){
        printf("error query1:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    char query[1024] = {0};
    sprintf(query, "select parentId from virtualFile where id = %d", id);

    ret = doQuery(query, &conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    MYSQL_RES *result = mysql_store_result(conn);
    if(result == NULL){
        printf("error result: %s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    int rows = mysql_num_rows(result);
    if(rows == 0){
        // 文件不存在返回1
        mysql_free_result(result);
        mysql_close(conn);
        return 1;
    }
    MYSQL_ROW row;
    if((row = mysql_fetch_row(result)) == NULL){
        return EXIT_FAILURE;
    }
    *pparentCode = atoi(row[0]);
    mysql_free_result(result);
    mysql_close(conn);
    return 0;
}

// 在本地文件表中插入新数据
int addLocalFile(char *md5Str, char *realName){
     MYSQL *conn;
    int ret = mysqlConnect(&conn);
    if (ret != 0){
        return EXIT_FAILURE;
    }
    ret = mysql_query(conn, "set names 'utf8'");
    if(ret != 0){
        printf("error query1:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    char query[1024] = {0};

    bzero(query, sizeof(query));
    sprintf(query, "insert into localFiles(md5, linkNum, realFileName) values('%s', 1, '%s')", md5Str, realName);
    ret = doQuery(query, &conn);
    if (ret != 0){
        return EXIT_FAILURE;
    }
    mysql_close(conn);
    return 0;
}

int addVirtualDir(int parentId, char *fileName, int ownerId){
    MYSQL *conn;
    int ret = mysqlConnect(&conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    ret = mysql_query(conn, "set names 'utf8'");
    if(ret != 0){
        printf("error query1:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    char query[1024] = {0};
    sprintf(query, "insert into virtualFile(parentId, fileName, ownerId, md5, filesize, type) \
            values(%d, '%s', %d, '0', 0, 'd')", parentId, fileName, ownerId);
    ret = doQuery(query, &conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    mysql_close(conn);
    return 0;
}

int addVirtualFile(int parentId, char *fileName, int ownerId, char *md5Str, int filesize){
    MYSQL *conn;
    int ret = mysqlConnect(&conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    ret = mysql_query(conn, "set names 'utf8'");
    if(ret != 0){
        printf("error query1:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    char query[1024] = {0};
    sprintf(query, "insert into virtualFile(parentId, fileName, ownerId, md5, filesize, type) \
            values(%d, '%s', %d, '%s', %d, 'f')", parentId, fileName, ownerId, md5Str, filesize);
    ret = doQuery(query, &conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    mysql_close(conn);
    return 0;
}

// 删除虚拟文件/目录
int delVirtualFile(int code, int userId){
    MYSQL *conn;
    int ret = mysqlConnect(&conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    ret = mysql_query(conn, "set names 'utf8'");
    if(ret != 0){
        printf("error query1:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    char query[1024] = {0};
    sprintf(query, "delete from virtualFile where id = %d", code);
    ret = doQuery(query, &conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }

    bzero(query, sizeof(query));
    sprintf(query, "delete from virtualFile where parentId = %d and ownerId = %d", code, userId);
    ret = doQuery(query, &conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }

    mysql_close(conn);
    return 0;
}

int ifLocalExist(char *md5Str){
    MYSQL *conn;
    int ret = mysqlConnect(&conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    ret = mysql_query(conn, "set names 'utf8'");
    if(ret != 0)
    {
        printf("error query1:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    char query[1024] = {0};

    // 查询文件是否已在表中存在
    bzero(query, sizeof(query));
    sprintf(query, "select * from localFiles where md5 like '%s'", md5Str);
    ret = doQuery(query, &conn);
    if (ret != 0){
        return EXIT_FAILURE;
    }
    MYSQL_RES *result = mysql_store_result(conn);// 这里如果用use不会真正获得数据，rows仍为0
    if (ret != 0)
    {
        printf("error query:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    int rows = mysql_num_rows(result);
    if(rows == 0){
        // 文件不存在返回1
        mysql_free_result(result);
        return 1;
    }
    mysql_free_result(result);
    mysql_close(conn);
    // 文件存在返回0
    return 0;
}

int findCodeFiles(int netFd, int code, int userId){
    MYSQL *conn;
    int ret = mysqlConnect(&conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    ret = mysql_query(conn, "set names 'utf8'");
    if(ret != 0){
        printf("error query1:%s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    char query[1024] = {0};
    sprintf(query, "select fileName from virtualFile where parentId = %d and ownerId = %d", code, userId);
    ret = doQuery(query, &conn);
    if(ret != 0){
        return EXIT_FAILURE;
    }
    MYSQL_RES *result = mysql_use_result(conn);
    if(result == NULL){
        printf("error result: %s\n", mysql_error(conn));
        return EXIT_FAILURE;
    }
    MYSQL_ROW row;
    train_t train;
    while((row = mysql_fetch_row(result)) != NULL)
    {
        train.length = strlen(row[0]);
        bzero(train.data, sizeof(train.data));
        strcpy(train.data ,row[0]);
        send(netFd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);
    }
    // 发送长度0表示结束
    train.length = 0;
    send(netFd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);
    mysql_free_result(result);
    mysql_close(conn);
    return EXIT_FAILURE;
}

